毕业季|b站《入海》评论爬取
本文作者:张馨月
文字编辑:朱巧利
技术总编:张计宝
Stata暑期线上课程火热招生中~
爬虫俱乐部将于2020年7月11日至14日在线上举行为期四天的Stata编程技术定制培训。课程通过案例教学模式,旨在帮助大家在短期内掌握Stata的基本命令、编程、数据处理以及结果输出等技术,并针对最新版Stata中的实用新功能做出详细介绍,包括框架功能(frame:读入多个数据集)等等。同时,此次云端课程提供录播,提供线上答疑。详细培训大纲及报名方式请查看《Stata云端课程来啦》,或点击文末阅读原文直接提交报名信息呦~
受疫情的影响,2020年的毕业季有些不同,从云毕业照、云答辩到云端毕业典礼,往年的花式毕业流程在当下全靠网线维系。没能完整的告别是许多人的遗憾,而这样特殊的“云毕业”也将成为这届毕业生难忘的记忆。今天,小编来带领大家爬取b站《入海》MV的评论并制作词云图,愿即将跃入人海的每一位毕业生,无论奔涌在哪个浪潮里,都能在自己的生活中掀起巨浪。
(爬取链接:
https://www.bilibili.com/video/BV1tC4y1H7yz)
本文的主要内容如下;
1.获取网页链接
2.单页内容抓取
3.所有页面抓取
4.词云图绘制
1. 获取网页链接
由于网页的源代码中没有关于评论的信息,我们需要找到保存评论的链接。点击F12进入开发者模式,并通过Ctrl+F查找评论中的一条内容,便可找到网页的真实链接。在Preview界面里,我们可以看到这个网页中保存了与评论有关的非常详细的内容:
当我们打开Headers中的网址时,页面会显示无法访问。不过,通过对网址进行分析,最终发现当仅保留URL参数中的pn(页数)、type(=1)、oid(视频id)、sort(1为按时间排序,2为按热度排序)时,便能成功查看网页内容:
根据这个链接,我们便可对评论内容进行爬取~
2. 单页内容抓取
由于评论的内容以json格式储存,我们首先生成一个变量储存URL,再用fileread()将源代码读入到一行,以便于后续对源代码进行拆分:
clear
set obs 1
gen url="https://api.bilibili.com/x/v2/reply?type=1&oid=795637027&pn=1&sort=2"
gen v=fileread(url)
对源代码和Preview中的内容进行观察,可以看到评论内容均保留在关键字"rpid"中,但是查找网页中"rpid"字段,会发现其字段数量远远超过每页评论的数量(20条),这是因为"rpid"不仅保留了页面中显示的评论内容,还保留了每条评论的回复以及对该视频的热评。因此,我们需要将三者进行区分。
首先,根据”hots”关键字,将本页的评论内容与热评拆分,并只保留结果的前半段:
split v,p("hots")
keep v1
接下来,根据”rpid”将每条评论和回复拆分开,并进行转置:
split v1,p(`""rpid""')
drop v1
sxpose,clear
通过进一步对源代码内容的观察,可以看到每条评论"parent"对应的值为0,而回复中"parent"对应的值为一串数字,所以我们可以据此来保留主评论的内容:
keep if ustrregexm(_var1,`""parent":0"',.)
这样,我们根据字段content":{"message":"和字段","plat"进行拆分,即可得到评论的内容;使用正则表达式对”uname”和”like”的信息进行提取,便能得到楼主名称和评论的点赞数:
split _var1,p(`""content":{"message":""')
split _var12,p(`"","plat""')
rename _var121 content
gen like = ustrregexs(1) if ustrregexm(_var11,`""like":(\d+)"')
gen name = ustrregexs(1) if ustrregexm(_var11,`""uname":"(.*?)""')
drop _var*
3. 所有网页抓取
首先,我们将上述内容根据页码写入循环,以抓取每页的评论内容。需要注意的是目前的评论共有1100页,但页数随会着评论数量不断增加,所以我们在这里设置最大值为2000,在循环爬取的过程中,如果匹配"parent":0后的数据集为空,就终止循环:
forvalues i=1/2000{
clear
set obs 1
gen url="https://api.bilibili.com/x/v2/reply?type=1&oid=795637027&pn=`i'&sort=2"
gen v=fileread(url)
split v,p("hots")
keep v1
split v1,p(`""rpid""')
drop v1
sxpose,clear
keep if ustrregexm(_var1,`""parent":0"',.)
if _N==0{
continue,break
}
split _var1,p(`""content":{"message":""')
split _var12,p(`"","plat""')
rename _var121 content
gen like = ustrregexs(1) if ustrregexm(_var11,`""like":(\d+)"')
gen name = ustrregexs(1) if ustrregexm(_var11,`""uname":"(.*?)""')
drop _var*
save "page_`i'"
}
接下来,将各页的内容合并:
clear all
fs page*.dta
foreach file in `r(files)'{
append using "`file'" //把上面生成的影评i.dta合并起来
}
最后,由于评论内容中包括许多表情(保留在[ ]中)、空白字符(\s)、回车符和换行符(\r \n),我们用正则表达式对这些内容进行替换:
replace content=ustrregexra(content,"\[.*?\]","")
replace content = ustrregexra(content,"\s","",.)
replace content = ustrregexra(content,"\\r","",.)
replace content = ustrregexra(content,"\\n","",.)
save "评论.dta",replace
*导出为txt文档
keep content
export delimited using content.txt,replace
4. 词云图制作
在往期推文《疫情下的家庭关系|《请回答1988》影评爬取》《高亮输出之唐诗作者》等当中,我们通过Stata与Python的交互并使用命令wordcloud来绘制词云图,该命令的使用非常方便,使用一行代码即可得到结果。在今天的推文中,为了绘制出特定形状的词云图,我们使用Python完成这一过程。
首先,导入我们需要使用的库:
import jieba
import re
from collections import Counter
import matplotlib.pyplot as plt
from wordcloud import WordCloud, STOPWORDS
接下来,进行分词和词频统计,并设置停用词表:
result=[]
text=open(r"content.txt","r",encoding="utf8").read()
text=re.sub(r'[0-9A-Za-z.【】、一。,!~\*]','',text) #过滤数字、字母和一些其他的干扰字符
jieba.load_userdict(r"tsdict.txt") #添加自定义词典
seg_list = jieba.lcut(text)
seg_list=filter(lambda word:len(word)>1,seg_list)#过滤长度为1的词
result.extend(seg_list) #将分词结果加入到列表result中
word_counts = Counter(result) # 对分词做词频统计
stopwords=set(STOPWORDS)
with open('停用词表.txt',encoding='UTF-8') as f:
stop_words=[i.strip() for i in f.readlines()]
for word in stop_words:
stopwords.add(word)
在上述操作之后,导入背景图,便可使用WordCloud来制作词云图:
photo_coloring = plt.imread('background.jpg')
w=WordCloud(
background_color='white', # 设置背景颜色
font_path="msyh.ttc", #设置输出词云的字体为微软雅黑
width=400, height=800, #设置词云图的宽度,高度
max_words=200,
min_font_size=6,
stopwords=stopwords ,
mask=photo_coloring #设置词云形状
)
wordcloud=w.generate_from_frequencies(word_counts) #加载词云文本
到这里,我们以完成了基本步骤,为了让图片的色彩更加丰富,小编在这里导入一张渐变色的背景图片,操作如下:
#设置背景色
from wordcloud import ImageColorGenerator
from PIL import Image
import numpy as np
image=Image.open('color.jpg')
graph=np.array(image)
image_color=ImageColorGenerator(graph)
#展示图片
wordcloud=w.recolor(color_func=image_color)
plt.figure(figsize = (40,20))
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis("off") #设置显示的词云图中无坐标轴
plt.show()
这样,我们便可得到文章开头显示的图片。
今天的分享就到这里。祝各位早睡早起,未来可期~
关于我们
微信公众号“Stata and Python数据分析”分享实用的stata、python等软件的数据处理知识,欢迎转载、打赏。我们是由李春涛教授领导下的研究生及本科生组成的大数据处理和分析团队。
1)必须原创,禁止抄袭;
2)必须准确,详细,有例子,有截图;
注意事项:
1)所有投稿都会经过本公众号运营团队成员的审核,审核通过才可录用,一经录用,会在该推文里为作者署名,并有赏金分成。
2)邮件请注明投稿,邮件名称为“投稿+推文名称”。
3)应广大读者要求,现开通有偿问答服务,如果大家遇到有关数据处理、分析等问题,可以在公众号中提出,只需支付少量赏金,我们会在后期的推文里给予解答。